前面介绍了Otto的使用情况,下面开始进入Otto的源码分析之旅。
首先来看看构造函数:
构造函数
|
|
默认参数enforcer=ThreadEnforcer.MAIN,identifier=DEFAULT_IDENTIFIER,handlerFinder=HandlerFinder.ANNOTATED。下面来看看这些参数是什么意思:
ThreadEnforce
ThreadEnforce是一个接口,enforce()方法用于检查当前的线程是否为指定的线程类型
|
|
不带参数的构造函数默认使用ThreadEnforcer.MAIN,表示enforce()方法必须在主线程上执行。
identifier
identifier为Bus对象的名字,debug用
HandlerFinder
HandlerFinder用于在注册/反注册的时候查找Subscriber和Produce,后文会对其展开源码级别的解析。默认使用HandlerANNOTATED,表示使用注解来进行查找。
其他
除上述以外,Bus类还有两个成员变量handlersByType和producersByType:
|
|
注册/反注册事件
如下所示要成为订阅者HandlerEvent,只需将其注册到bus,然后使用@Subscribe注解标记回调处理方法即可。回调方法要求可见性为public,有且仅有一个参数,类型为订阅的event。
|
|
@Subsrible
首先看一下@Subscribe注解:
|
|
RetentionPolicy.RUNTIME表示它是运行时的注解,ElementType.METHOD表示用于注解方法。
register()
register流程:
|
|
register方法主要做了三件事情:触发新的Producer;注册新的event-handler关系;触发旧的Producer。另外有两点要注意:
- 在保证线程安全的情况下,使用CopyOnWriteArraySet作为保存event和handler的容器,可以大大提高效率。
- 由于register方法没有加锁,所有在3-1中,尽管已经检查了handlers是否存在,但仍需使用putIfAbsent来保存handler。
HandlerFinder
注意到Bus通过HandlerFinder来查找object上的producer和subscriber,接下来看一下HanderFinder的实现:
|
|
其中findAllProducers方法返回某event type对应的EventProducers,findAllSubscribers返回某event type对应的EventHandler集合。
EventProducer
EventProducer是producer方法的包装类,源码如下:
|
|
其中 produceEvent方法用于获得event。可以看出Otto要求produce方法不能有参数。
EventHandler
EventHandler是一个event handler方法(事件回调)的包装类,源码如下:
|
|
其中handlEvent方法用于在object上调用handle方法(事件回调),传入event对象。Otto要求event handler方法只能有一个参数就是event handler类。
dispatchProducerResultToHandler()
dispatchProducerResultToHandler方法用于将Producer产生的event分发给对应的handler,源码如下所示:
|
|
主要使用了Producer的produceEvent()获取event对象后,调用EventHandler的handleEvent()方法处理事件。
unregister()
Bus类的unregister()方法用于解除目标对象和Bus之间的关联关系,包括对象上的producer方法,subscriber方法,源码如下所示:
|
|
投递事件
post()
简单的事件投递过程如下:
|
|
下面来看下post方法实现的源码:
|
|
注意两点:
- 发送一个Event时,订阅了Event父类的Subscriber方法也会被调用
- 事件被放到调用者所在线程的队列里依次分发
flattenHierarchy()
进行post操作时,首先会通过flattenHierarchy方法获得event的所有父类或接口的集合:
|
|
Dispatch Queue
通过post方法投递的event首先会放到当前线程所在的Dispatch Queue中,然后依次分发。Bus类有如下成员属性:
|
|
eventsToDispatch是一个ThreadLocal对象,通过initialValue()方法,eventsToDispatch每次在新的线程上调用的时候都会生成新的ConcurrentLinkedQueue实例。event是通过enqueueEvent方法放到queue中的,下面看看equeueEvent()的实现:
|
|
offer()方法会将EventWithHandler对象放到当前线程的queue的尾部。offer方法和add方法的区别在于,当无法插入(例如空间不够)情况下会返回false,而不是抛出异常。EventWithHandler类对event和handler的关系进行了简单的包装,实现如下:
|
|
接下来看看dispatchQueuedEvents方法的实现:
|
|
值得注意的是,所有subscrible方法抛出的异常都会在这里捕获,捕获到异常以后event分发过程即停止,直到下一次在该线程上调用post为止。
结构图
Otto的总体结构如下表示
|
|